package com.tanhua.server.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.tanhua.autoconfig.template.OssTemplate;
import com.tanhua.commons.utils.Constants;
import com.tanhua.dubbo.api.CommentApi;
import com.tanhua.dubbo.api.MovementApi;
import com.tanhua.dubbo.api.UserInfoApi;
import com.tanhua.dubbo.api.VisitorsApi;
import com.tanhua.model.domain.UserInfo;
import com.tanhua.model.enums.CommentType;
import com.tanhua.model.mongo.Comment;
import com.tanhua.model.mongo.Movement;
import com.tanhua.model.mongo.Visitors;
import com.tanhua.model.vo.ErrorResult;
import com.tanhua.model.vo.MovementsVo;
import com.tanhua.model.vo.PageResult;
import com.tanhua.model.vo.VisitorsVo;
import com.tanhua.server.exception.BusinessException;
import com.tanhua.server.intercepter.UserThreadLocal;
import com.tanhua.server.service.MovementService;
import org.apache.commons.lang.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;


@Service
public class MovementServiceImpl implements MovementService {

    @Autowired
    private OssTemplate ossTemplate;

    @DubboReference
    private UserInfoApi userInfoApi;

    @DubboReference
    private MovementApi movementApi;

    //注入缓存
    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @DubboReference
    private VisitorsApi visitorsApi;

    @DubboReference
    private CommentApi commentApi;


    /**
     * 查询自己的动态
     */
    @Override
    public PageResult findMyAll(Integer page, Integer pagesize, Long userId) {
        //1、根据用户id，调用API查询个人动态内容（PageResult  -- Movement）
        PageResult pr = movementApi.findByuserId(userId, page, pagesize);
        //2、获取PageResult中的item列表对象
        List<Movement> items = (List<Movement>) pr.getItems();
        //3.非空判断
        if (items == null) {
            return pr;
        }
        //循环数据列表
        UserInfo byId = userInfoApi.findById(userId);

       /* ArrayList<MovementsVo> list = new ArrayList<>();
        for (Movement item : items) {
            //5、一个Movement构建一个Vo对象
            MovementsVo vo = MovementsVo.init(byId, item);
            list.add(vo);
        }*/

        //TODO JOK-8 循环数据列表
        List<MovementsVo> list = items.parallelStream().map(item ->
                MovementsVo.init(byId, item)
        ).collect(Collectors.toList());

        //构建返回值
        pr.setItems(list);
        return pr;
    }

    /**
     * 发布动态:
     */
    @Override
    public void publishMovement(Movement movement, MultipartFile[] imageContent) throws IOException {
        //1.检查参数:发布内容是否存在
        if (StringUtils.isEmpty(movement.getTextContent())) {
            throw new BusinessException(ErrorResult.contentError());
        }
        //2.获取当前用户id
        Long userId = UserThreadLocal.getUserId();

        //3.将文件内容上传到阿里云oss获取地址
        ArrayList<String> list = new ArrayList<>();
        for (MultipartFile multipartFile : imageContent) {
            String upload =
                    ossTemplate.upload(multipartFile.getOriginalFilename(),
                            multipartFile.getInputStream());
            list.add(upload);
        }

        //4.将数据封住到Movement对象
        movement.setUserId(userId);
        movement.setMedias(list);
        //5.调用api发布
        movementApi.publish(movement);
    }

    /**
     * 查询好友动态
     */
    @Override
    public PageResult findFriendMovements(Integer page, Integer pagesize) {
        //1.获取当前用户id
        Long userId = UserThreadLocal.getUserId();
        //2.调用api查询好友动态
        List<Movement> list = movementApi.findFriendMovements(page, pagesize, userId);
        //3.判断列表是否为空
        return getPageResult(page, pagesize, list);
    }

    //抽取公共方法
    private PageResult getPageResult(Integer page, Integer pagesize, List<Movement> list) {
        if (CollUtil.isEmpty(list)) {
            return new PageResult();
        }
        //4.提取动态发布人的id列表
        List<Long> userIds = CollUtil.getFieldValues(list, "userId", Long.class);
        //5.根据用户的id列表获取用户详情
        Map<Long, UserInfo> map = userInfoApi.findByIds(userIds, null);
        //6.一个Movement构建一个vo对象
        List<MovementsVo> collect = list.parallelStream()
                .filter(c -> map.get(c.getUserId()) != null)
                .map(movement -> {
                    return MovementsVo.init(map.get(movement.getUserId()), movement);
                }).collect(Collectors.toList());

       /* //6、一个Movement构造一个vo对象
        List<MovementsVo> vos = new ArrayList<>();
        for (Movement movement : list) {
            UserInfo userInfo = map.get(movement.getUserId());
            if(userInfo != null) {
                MovementsVo vo = MovementsVo.init(userInfo, movement);
                vos.add(vo);
            }
        }*/
        //7.构造PageResult并返回
        return new PageResult(page, pagesize, 0l, collect);
    }

    /**
     * 查询推荐动态列表
     *
     * @param page
     * @param pagesize
     * @return
     */
    @Override
    public PageResult findRecommendMovements(Integer page, Integer pagesize) {
        //1.从Redis当中获取动态数据
        String redisKey = Constants.MOVEMENTS_RECOMMEND + UserThreadLocal.getUserId();
        String redisValue = (String) redisTemplate.opsForValue().get(redisKey);
        //2.判断推荐数据是否存在
        List<Movement> list = Collections.EMPTY_LIST;
        if (StringUtils.isEmpty(redisValue)) {
            //3、如果不存在，调用API随机构造10条动态数据
            list = movementApi.randomMovements(pagesize);
        } else {
            //4.如果存在,处理pid数据
            String[] split = redisValue.split(",");
            //判断当前页的起始条数是否小于数组总数
            if ((page - 1) * pagesize < split.length) {
                List<Long> pids = Arrays.stream(split).skip((page - 1) * pagesize)
                        .limit(pagesize).map(e -> Long.valueOf(e))
                        .collect(Collectors.toList());

                list = movementApi.findMovementsByPids(pids);
            }
        }
        //6、调用公共方法构造返回值
        return getPageResult(page, pagesize, list);
    }


    /**
     * 查询单条动态详情
     *
     * @param movementId
     * @return
     */
    @Override
    public MovementsVo findRecommendById(String movementId) {
        //1、调用api根据id查询动态详情
        Movement movement = movementApi.findById(movementId);
        //2.转化为vo对象
        if (movement != null) {
            //查询该条动态对象的用户
            UserInfo info = userInfoApi.findById(movement.getUserId());
            //返回vo
            return MovementsVo.init(info, movement);
        } else {
            return null;
        }
    }


    //动态点赞
    @Override
    public Integer likeMovement(String movementId) {
        //1.调用api查询用户是否已经点赞
        Long userId = UserThreadLocal.getUserId();
        Boolean hasComment = commentApi.hasComment(movementId, userId, CommentType.LIKE);
        //2.如果已经点赞,抛出异常
        if (hasComment) {
            //throw new BusinessException(ErrorResult.error());
            disLikeMovement(movementId);
        }
        //3.调用Api保存点赞数据到MongoDB
        Comment comment = new Comment();
        comment.setPublishId(new ObjectId(movementId));  //点赞的动态id
        comment.setUserId(userId);  //点赞的id用户
        comment.setCommentType(CommentType.LIKE.getType());  //点赞
        comment.setCreated(System.currentTimeMillis());
        //4.添加点赞返回总记录数
        Integer count = commentApi.save(comment);
        //5.拼接redis的Key,将用户点赞数存入redis
        String key = "MOVEMENTS_INTERACT_KEY" + movementId;
        String hashKey = "MOVEMENT_LIKE_HASHKEY" + userId;
        redisTemplate.opsForHash().put(key, hashKey, 1);
        //返回总记录数
        return count;
    }


    //动态取消点赞
    @Override
    public Integer disLikeMovement(String movementId) {
        //1.首先查询自己有没有点赞,传入动态id,取消点赞用户,动态操作点赞的类型
        Long userId = UserThreadLocal.getUserId();
        Boolean aBoolean = commentApi.hasComment(movementId, userId, CommentType.LIKE);
        //分析:没有点赞就点赞,点赞了就取消掉
        if (!aBoolean) {
            //throw new BusinessException(ErrorResult.error());
            //没有点赞:调用上诉方法点赞
            likeMovement(movementId);
        }
        //2.调用api取消点赞,获取并返回总记录数
        Comment comment = new Comment();
        comment.setPublishId(new ObjectId(movementId));  //动态id
        comment.setUserId(userId);  //点赞的id用户
        comment.setCommentType(CommentType.LIKE.getType());  //点赞状态
        comment.setCreated(System.currentTimeMillis());
        //4.删除点赞返回总记录数
        Integer count = commentApi.delete(comment);
        //5删除redis当中的点赞记录
        String key = "MOVEMENTS_INTERACT_KEY" + movementId;
        String hashKey = "MOVEMENT_LIKE_HASHKEY" + userId;
        redisTemplate.opsForHash().delete(key, hashKey);
        return count;
    }

    //动态喜欢
    @Override
    public Integer loveMovement(String movementId) {
        //1.查询自己有没有喜欢该动态
        Long userId = UserThreadLocal.getUserId();
        Boolean aBoolean = commentApi.hasComment(movementId, userId, CommentType.LOVE);
        //1.1判断:喜欢过抛出异常
        if (aBoolean) {
            //throw new BusinessException(ErrorResult.error());
            //喜欢过,取消喜欢
            disloveMovement(movementId);
        }
        //1.2没有喜欢更新数据
        Comment comment = new Comment();
        comment.setPublishId(new ObjectId(movementId));  //动态id
        comment.setUserId(userId);    //喜欢的用户id
        comment.setCommentType(CommentType.LOVE.getType()); //love状态
        comment.setCreated(System.currentTimeMillis());
        //2.调用api保存喜欢数据,并返回当前记录数
        Integer count = commentApi.save(comment);
        //3.添加该记录数到redis当中
        String key = "MOVEMENTS_INTERACT_KEY" + movementId;
        String hashKey = "MOVEMENT_LOVE_HASHKEY" + userId;
        redisTemplate.opsForHash().put(key, hashKey, 1);
        return count;
    }

    //动态取消喜欢
    @Override
    public Integer disloveMovement(String movementId) {
        //1.首先查询自己有没有喜欢,传入动态id,用户id,动态操作类型
        Long userId = UserThreadLocal.getUserId();
        Boolean hasComment = commentApi.hasComment(movementId, userId, CommentType.LOVE);
        //没有可以调用上面喜欢方法喜欢
        if (!hasComment) {
            //throw new BusinessException(ErrorResult.error());
            //没有喜欢:调用上诉方法喜欢
            loveMovement(movementId);
        }
        //2.调用api取消喜欢,获取并返回总记录数
        Comment comment = new Comment();
        comment.setPublishId(new ObjectId(movementId));  //动态的id
        comment.setUserId(userId);  //喜欢的id用户
        comment.setCommentType(CommentType.LOVE.getType());  //喜欢状态
        comment.setCreated(System.currentTimeMillis());
        //4.删除喜欢返回总记录数
        Integer count = commentApi.delete(comment);
        //5删除redis当中的喜欢的记录
        String key = "MOVEMENTS_INTERACT_KEY" + movementId;
        String hashKey = "MOVEMENT_LOVE_HASHKEY" + userId;
        redisTemplate.opsForHash().delete(key, hashKey);
        return count;
    }


    /**
     * 查询谁看过我
     *
     * @return
     */
    @Override
    public List<VisitorsVo> queryVisitorsList() {
        //获取UserId
        Long userId = UserThreadLocal.getUserId();
        //查询访问时间
        String key = Constants.VISITORS_USER;
        String hashKey = String.valueOf(userId);
        String value = (String) redisTemplate.opsForHash().get(key, hashKey);

        //获取访问时间
        Long date = StringUtils.isEmpty(value) ? null : Long.valueOf(value);
        //2.调用Api查询数据列表
        List<Visitors> list = visitorsApi.queryMyVisitors(date, userId);
        if (CollUtil.isEmpty(list)) {
            return new ArrayList<>();
        }
        //3.提取来访用户id
        List<Long> visitorUserIds =
                CollUtil.getFieldValues(list, "visitorUserId", Long.class);
        //4.查看用户详情
        Map<Long, UserInfo> map =
                userInfoApi.findByIds(visitorUserIds, null);

        //5.封装到list<visitorsVo> vo
        //高级stream流方式
        List<VisitorsVo> vos = list.parallelStream()
                .filter(visitors ->
                        map.get(visitors.getVisitorUserId()) != null
                ).map(visitors ->
                        VisitorsVo.init(map.get(visitors.getVisitorUserId()), visitors))
                .collect(Collectors.toList());
        //6.设置当前访问时间
        redisTemplate.opsForHash().put(key, hashKey, System.currentTimeMillis());

        return vos;
    }
}